package com.czy.enchantmentvisualization.start;

import com.czy.enchantmentvisualization.EnchantmentVisualizationApplication;
import com.czy.enchantmentvisualization.common.GeneralInformation;
import com.czy.enchantmentvisualization.domain.entity.Enchantment;
import com.czy.enchantmentvisualization.domain.entity.Rarity;
import com.czy.enchantmentvisualization.domain.entity.Type;
import com.czy.enchantmentvisualization.domain.vo.EnchantmentVo;
import com.czy.enchantmentvisualization.utils.FileNameUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

@Component
@Slf4j
public class Start implements ApplicationRunner {

    private static final List<String> enchantmentList = new ArrayList<>();
    private static final List<String> configList = new ArrayList<>();
    private static final List<String> configPath = Arrays.asList("vanillaenchants.yml", "types.yml", "targets.yml", "rarity.yml", "lrcdb.yml", "lang.yml", "config.yml", "chains.yml");
    private static final String excludePath = "_example.yml";
    private static final List<String> listProperty = Arrays.asList("targets", "conflicts");
    private static final List<String> mapProperty = List.of("placeholders");
    private static final List<Enchantment> enchantments = new ArrayList<>();
    private static final List<EnchantmentVo> enchantmentVos = new ArrayList<>();
    private static final List<String> isFieldList = Arrays.asList("display-name", "description", "placeholder", "placeholders", "targets", "conflicts", "max-level", "tradeable", "discoverable", "enchantable");
    private static final String isFieldRarityString = "rarity";
    private static final String isFieldtypeString = "type";
    private static final Map<String, String> targetsMap = new HashMap<>();
    //    private static final Map<String, String> rarityMap = new HashMap<>();
    private static final List<Rarity> rarityList = new ArrayList<>();
    private static final List<Type> typeList = new ArrayList<>();
    private static final List<String> allTargets = Arrays.asList("镐","斧","锄","锹","剑","头盔","胸甲","护腿","鞋子","三叉戟","弓","弩","剪刀","盾","鱼竿","打火石","萝卜钓竿","鞘翅");
    private static final List<String> armor = Arrays.asList("头盔","胸甲","护腿","鞋子");
    private static final List<String> imageList = new ArrayList<>();

    @Autowired
    private ResourceLoader resourceLoader;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 先通过类路径获取文件的路径 (路径无法使用 但是从 static 开始就可以用 resourceLoader.getResource( static开始的路径---前面需要加上classpath:).getInputStream() 获取到)
        ClassLoader classLoader = EnchantmentVisualizationApplication.class.getClassLoader();


        init(classLoader);
        initImages(classLoader);
        initRarity();
        initType();
        initEnchantments();
        initEnchantmentVos();
        initVanillaEnchantment();
        initTargetsMap();

        toVo();

//        GeneralInformation.enchantmentVos.forEach(item -> System.out.println(item.getRarity()));
//        GeneralInformation.enchantmentVos.forEach(item -> System.out.println(item.getRarity()));
    }

    /**
     * 初始化类型信息
     * @throws IOException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void initType() throws IOException, NoSuchFieldException, IllegalAccessException {
        for (String filePath : configList) {
            if ("types".equals(FileNameUtil.getYmlSuffix(filePath))) {
                Yaml yaml = new Yaml();
                Map<String, Object> load = yaml.load(resourceLoader.getResource(filePath).getInputStream());
                List<Map<String, Object>> list = (List<Map<String, Object>>) load.get("types");
                for (Map<String, Object> map : list) {
                    Type type = new Type();
                    for (String key : map.keySet()) {
                        if("format".equals(key)) continue;

                        Field declaredField = type.getClass().getDeclaredField(conversionKey(key));
                        declaredField.setAccessible(true);
                        switch (key) {
                            case "id" -> declaredField.set(type, map.get(key));
                            case "limit" -> declaredField.set(type, Integer.valueOf(map.get(key).toString()));
                            case "high-level-bias" -> declaredField.set(type, Double.valueOf(map.get(key).toString()));
                            case "no-grindstone" -> declaredField.set(type, Boolean.valueOf(map.get(key).toString()));
                        }
                    }
                    typeList.add(type);
                }
            }
        }
    }

    /**
     * 初始化图标路径
     * @param classLoader
     * @throws IOException
     */
    private void initImages(ClassLoader classLoader) throws IOException {
        Enumeration<URL> resources = classLoader.getResources("static/images");
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            // 通过URL获取文件路径
            try {
                Path directoryPath = Paths.get(resource.toURI());

                // 遍历目录下的文件
                Files.walk(directoryPath)
                        .filter(Files::isRegularFile)
                        .forEach(filePath -> {
                            String substring = "classpath:" + filePath.toString().substring(filePath.toString().indexOf("static"));
                            imageList.add(substring);
                        });
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
        GeneralInformation.imageList.addAll(imageList);
    }

    private static void toVo() {
        for (EnchantmentVo enchantmentVo : enchantmentVos) {
            List<String> conflicts = enchantmentVo.getConflicts();
            List<String> targets = enchantmentVo.getTargets();
            EnchantmentVo ev = new EnchantmentVo();
            BeanUtils.copyProperties(enchantmentVo,ev,"conflicts","targets");

            for (String conflict : conflicts) {
                for (EnchantmentVo vo : enchantmentVos) {
                    if(vo.getCodeName().equals(conflict)){
                        ev.getConflicts().add(vo.getDisplayName());
                    }
                }
            }

            for (String target : targets) {
                if("all".equals(target)){
                    ev.getTargets().addAll(allTargets);
                }else if ("armor".equals(target)){
                    ev.getTargets().addAll(armor);
                }else {
                    String s = targetsMap.get(target);
                    ev.getTargets().add(s);
                }
            }

            GeneralInformation.enchantmentVos.add(ev);
        }
    }

    /**
     * 初始化稀有度信息
     * @throws IOException
     */
//    private void initRarity() throws IOException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//        for (String filePath : configList) {
//            if ("rarity".equals(FileNameUtil.getYmlSuffix(filePath))) {
//                Yaml yaml = new Yaml();
//                Map<String, Object> load = yaml.load(resourceLoader.getResource(filePath).getInputStream());
////                System.out.println(load);
//                List<Map<String, String>> list = (List<Map<String, String>>) load.get("rarities");
//                for (Map<String, String> map : list) {
//                    Rarity rarity = new Rarity();
//                    for (String key : map.keySet()) {
//                        Field declaredField = rarity.getClass().getDeclaredField(conversionKey(key));
//                        declaredField.setAccessible(true);
//                        Class<?> type = declaredField.getType();
//                        if(!type.equals(String.class)){
//                            Method valueOf = type.getMethod("valueOf",String.class);
//                            declaredField.set(rarity, valueOf.invoke(null,map.get(key)));
//                        }else {
//                            declaredField.set(rarity, map.get(key));
//                        }
//                    }
//                    rarityList.add(rarity);
////                    String codeName = map.get("id");
////                    String displayName = map.get("display-name");
////                    rarityMap.put(codeName, displayName);
//                }
//            }
//        }
//    }

    private void initRarity() throws IOException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        for (String filePath : configList) {
            if ("rarity".equals(FileNameUtil.getYmlSuffix(filePath))) {
                Yaml yaml = new Yaml();
                Map<String, Object> load = yaml.load(resourceLoader.getResource(filePath).getInputStream());
                List<Map<String, Object>> list = (List<Map<String, Object>>) load.get("rarities");
                for (Map<String, Object> map : list) {
                    Rarity rarity = new Rarity();
                    for (String key : map.keySet()) {
                        Field declaredField = rarity.getClass().getDeclaredField(conversionKey(key));
                        declaredField.setAccessible(true);
                        switch (key) {
                            case "id", "display-name" -> declaredField.set(rarity, map.get(key));
                            case "table-chance", "villager-chance", "loot-chance" ->
                                    declaredField.set(rarity, Double.valueOf(map.get(key).toString()));
                            case "minimum-level" -> declaredField.set(rarity, Integer.valueOf(map.get(key).toString()));
                        }
                    }
                    rarityList.add(rarity);
                }
            }
        }
    }

    /**
     * 初始化物品信息
     * @throws IOException
     */
    private void initTargetsMap() throws IOException {
        for (String filePath : configList) {
            if ("targets".equals(FileNameUtil.getYmlSuffix(filePath))) {
                Yaml yaml = new Yaml();
                Map<String, Object> load = yaml.load(resourceLoader.getResource(filePath).getInputStream());
                List<Map<String, String>> list = (List<Map<String, String>>) load.get("targets");
                for (Map<String, String> map : list) {
                    String codeName = map.get("id");
                    String displayName = map.get("display-name");
                    targetsMap.put(codeName, displayName);
//                    System.out.println(codeName + " " + displayName);
                }
            }
        }
    }

    /**
     * 初始化原版附魔
     * @throws IOException
     */
    private void initVanillaEnchantment() throws IOException {
        for (String filePath : configList) {
            if ("vanillaenchants".equals(FileNameUtil.getYmlSuffix(filePath))) {
                Yaml yaml = new Yaml();
                Map<String, Object> load = yaml.load(resourceLoader.getResource(filePath).getInputStream());
                for (String key : load.keySet()) {
                    Map<String, String> map = (HashMap<String, String>) load.get(key);
                    for (String mapKey : map.keySet()) {
                        if (mapKey.equals("name")) {
                            EnchantmentVo vo = new EnchantmentVo();
                            vo.setDisplayName(map.get(mapKey));
                            vo.setCodeName(key);
                            vo.setBool(true);
                            enchantmentVos.add(vo);
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * 进一步初始化附魔信息
     */
    private void initEnchantmentVos() {
        for (Enchantment enchantment : enchantments) {
            EnchantmentVo vo = new EnchantmentVo();
            BeanUtils.copyProperties(enchantment, vo);

            vo.setDescription(vo.getDescription().replaceAll("&.", ""));

            String placeholder = vo.getPlaceholder();
            Map<String, String> placeholders = vo.getPlaceholders();

            if (placeholder != null) {
                vo.setDescription(vo.getDescription().replace("%placeholder%", "(" + vo.getPlaceholder() + ")"));
            } else if (placeholders != null) {
                for (String key : placeholders.keySet()) {
                    vo.setDescription(vo.getDescription().replace("%" + key + "%", "(" + placeholders.get(key) + ")"));
                }
            }
            vo.setDescription(vo.getDescription().replace("%level%", "level"));
            enchantmentVos.add(vo);
        }
    }

    /**
     * 初始化附魔信息
     * @throws IOException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private void initEnchantments() throws IOException, NoSuchFieldException, IllegalAccessException {
        for (String enchantment : enchantmentList) {
            Yaml yaml = new Yaml();

            Map<String, Object> load = yaml.load(resourceLoader.getResource(enchantment).getInputStream());
            Enchantment enchantment1 = new Enchantment();
            for (String key : load.keySet()) {
                if (isList(key)) {
                    List<String> list = toList(load.get(key));
                    Field declaredField = enchantment1.getClass().getDeclaredField(conversionKey(key));
                    declaredField.setAccessible(true);
                    declaredField.set(enchantment1, list);
                } else if (isMap(key)) {
                    Map<String, String> map = toMap(load.get(key));
                    Field declaredField = enchantment1.getClass().getDeclaredField(conversionKey(key));
                    declaredField.setAccessible(true);
                    declaredField.set(enchantment1, map);
                } else if (isField(key)) {
                    Field declaredField = enchantment1.getClass().getDeclaredField(conversionKey(key));
                    declaredField.setAccessible(true);
                    declaredField.set(enchantment1, load.get(key));
                } else if (isFieldRarity(key)) {
                    Field declaredField = enchantment1.getClass().getDeclaredField(conversionKey(key));
                    declaredField.setAccessible(true);
                    String id = (String) load.get(key);
                    for (Rarity rarity : rarityList) {
                        if(Objects.equals(rarity.getId(),id)){
                            declaredField.set(enchantment1, rarity);
                            break;
                        }
                    }
                } else if(isFieldType(key)) {
                    Field declaredField = enchantment1.getClass().getDeclaredField(conversionKey(key));
                    declaredField.setAccessible(true);
                    String id = (String) load.get(key);
                    for (Type type : typeList) {
                        if(Objects.equals(type.getId(),id)){
                            declaredField.set(enchantment1, type);
                            break;
                        }
                    }
                }
            }

            enchantment1.setCodeName(FileNameUtil.getYmlSuffix(enchantment));
            enchantments.add(enchantment1);
        }
    }

    private Boolean isFieldType(String key) {
        return isFieldtypeString.equals(key);
    }

    private Boolean isFieldRarity(String key) {
        return isFieldRarityString.equals(key);
    }

    /**
     * 初始化附魔路径
     * @param classLoader
     * @throws IOException
     */
    private static void init(ClassLoader classLoader) throws IOException {
        Enumeration<URL> resources = classLoader.getResources("static/EcoEnchants");
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            // 通过URL获取文件路径
            try {
                Path directoryPath = Paths.get(resource.toURI());

                // 遍历目录下的文件
                Files.walk(directoryPath)
                        .filter(Files::isRegularFile)
                        .forEach(filePath -> {
                            // 获取字符流
                            boolean config = false;
                            for (String path : configPath) {
                                if (filePath.endsWith(path)) {
                                    config = true;
                                    break;
                                }
                            }

                            String substring = "classpath:" + filePath.toString().substring(filePath.toString().indexOf("static"));
                            if (config) {
                                configList.add(substring);
                            } else if (!filePath.endsWith(excludePath)) {
                                enchantmentList.add(substring);
                            }
                        });
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
    }

    private Boolean isField(String key) {
        return isFieldList.contains(key);
    }

    private Map<String, String> toMap(Object o) {
        return (HashMap<String, String>) o;
    }

    private List<String> toList(Object o) {
        return (List<String>) o;
    }

    private Boolean isList(String key) {
        return listProperty.contains(key);
    }

    private Boolean isMap(String key) {
        return mapProperty.contains(key);
    }

    private String conversionKey(String key) {
        String[] split = key.split("-");
        if (split.length <= 1) {
            return key;
        }

        StringBuilder result = new StringBuilder(split[0]);
        for (int i = 1; i < split.length; i++) {
            result.append(Character.toUpperCase(split[i].charAt(0)))
                    .append(split[i].substring(1));
        }

        return result.toString();
    }
}
